home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / scheme / pcscheme / geneva / sources.exe / SOURCES / S / PEEPHOLE.S < prev    next >
Encoding:
Text File  |  1993-10-24  |  17.0 KB  |  574 lines

  1. ; PEEPHOLE.S
  2. ;************************************************************************
  3. ;*                                    *
  4. ;*        PC Scheme/Geneva 4.00 Scheme code            *
  5. ;*                                    *
  6. ;* (c) 1985-1988 by Texas Instruments, Inc. See COPYRIGHT.TXT        *
  7. ;* (c) 1992 by L. Bartholdi & M. Vuilleumier, University of Geneva    *
  8. ;*                                    *
  9. ;*----------------------------------------------------------------------*
  10. ;*                                    *
  11. ;*        Post-Code Generation Optimization            *
  12. ;*                                    *
  13. ;*----------------------------------------------------------------------*
  14. ;*                                    *
  15. ;* Created by: David Bartley        Date: Oct 1985            *
  16. ;* Revision history:                            *
  17. ;* - 1 Jun 87:    Modified p2-subst, so as not to monkey with varargs (rb)*
  18. ;* - 3 Jun 87:    Modified p1 register substitution to understand " (tc)    *
  19. ;* - 18 Jun 92:    Renaissance (Borland Compilers, ...)            *
  20. ;*                                    *
  21. ;*                    ``In nomine omnipotentii dei''    *
  22. ;************************************************************************
  23.  
  24. ; Note:  The optimization TEST+JUMP-NULL? ==> JUMP-NOT-TEST has not been
  25. ;        implemented because peep2 can't reliably tell when TEST is dead.
  26.  
  27. (define pcs-postgen
  28.   (lambda (code)
  29.     (letrec
  30.      (
  31. ;----!
  32.  
  33.   (peep1
  34.    (lambda (code)
  35.      (cond (pcs-permit-peep-1 (p1 code '()))
  36.        (pcs-permit-peep-2 (%reverse! code))
  37.        (else code))))
  38.  
  39.   (p1
  40.    (lambda (next acc)
  41.      (if (null? next)
  42.      (begin
  43.         (p1-forget-all)
  44.         acc)
  45.      (let ((rest  (cdr next))
  46.            (instr (car next)))
  47.        (cond ((or (atom? instr)            ; label
  48.               (number? (car instr)))        ; label
  49.           (when (and acc
  50.                  (cdr acc)
  51.                  (not (atom? (car acc)))
  52.                  (eq? (caar acc) 'JUMP)
  53.                  (equal? (cadar acc) instr))
  54.             (set! acc (cdr acc)))   ; delete "JUMP $+1"
  55.           (p1-forget-all))
  56.          ((memq (car instr) '(JUMP CALL LIVE))
  57.           (p1-forget-all))
  58.          ((eq? (car instr) 'LOAD)
  59.           (p1-propagate (cddr instr))        ; src reg
  60.           (p1-forget (cdr instr))        ; dest reg
  61.           (p1-remember (cadr instr)        ; dest <== src
  62.                    (caddr instr))
  63.          )
  64.          ((memq (car instr) '(%graphics %esc %mouse))    ; variable-length instructions
  65.                    ; v-len instructions assumes the dest reg (cadr instr) will
  66.           ; be equal to the third operand (cadddr instr). This is due
  67.           ; to the way code is generated in pgencode.
  68.           (let ((dest (cadr instr)))
  69.             (p1-propagate-all (cdr instr))
  70.              (p1-forget (cdr instr))        ; dest reg
  71.             (p1-forget dest)            ; old dest reg
  72.                  (p1-remember (cadr instr)        ; dest <== src
  73.                        (cadddr instr))
  74.             (p1-remember dest             ; old dest <== src
  75.                  (cadddr instr))
  76.           )
  77.          )
  78.          ((not (atom? (cdr instr)))
  79.           (p1-propagate-all (cddr instr))    ; src regs
  80.           (p1-forget (cdr instr)))        ; dest reg
  81.          (else '()))
  82.        (set-cdr! next acc)
  83.        (p1 rest next)))))
  84.  
  85.   (p1-propagate
  86.    (lambda (s*)   ; (src ...)
  87.      (when (not (atom? s*))
  88.        (let ((s (car s*)))
  89.          (when (number? s)
  90.            (let ((sub (vector-ref reg-table s)))
  91.              (when sub                ; any sub
  92.                (set-car! s* sub))))))))
  93.  
  94.   (p1-propagate-all
  95.    (lambda (s*)   ; (src ...)
  96.      (when (not (atom? s*))
  97.        (let ((s (car s*)))
  98.          (when (number? s)
  99.            (let ((sub (vector-ref reg-table s)))
  100.              (when (number? sub)        ; regs only
  101.                (set-car! s* sub)))))
  102.        (p1-propagate-all (cdr s*)))))        ; cdr down
  103.  
  104.   (p1-remember
  105.    (lambda (dest src)
  106.      (when (or (number? src)                ; reg?
  107.            (and (not (atom? src))            ; constant
  108.             (eq? (car src) 'quote)))
  109.        (vector-set! reg-table dest src)
  110.        (set! reg-table-max
  111.          (max reg-table-max
  112.               (if (and (number? src)(> src dest))
  113.               src
  114.               dest))))))
  115.  
  116.   (p1-forget
  117.    (lambda (d*)   ; (dest ...)
  118.      (when (not (atom? d*))
  119.        (let ((d (car d*)))
  120.          (when (number? d)   ; reg
  121.            (vector-set! reg-table d #F)
  122.            (p1-forget-uses d))))))
  123.  
  124.   (p1-forget-uses
  125.    (lambda (reg)
  126.      (letrec ((loop (lambda (v i reg)
  127.               (when (not (negative? i))
  128.                 (if (equal? (vector-ref v i) reg)
  129.                 (vector-set! v i #F))
  130.                 (loop v (sub1 i) reg)))))
  131.       (loop reg-table reg-table-max reg))))
  132.  
  133.   (p1-forget-all
  134.    (lambda ()
  135.      (vector-fill! reg-table #F)))
  136.  
  137.  
  138. ;;; p2 -- peephole optimizer pass 2
  139.  
  140. ;;; Purposes:
  141. ;;;
  142. ;;;    1. Destructively reverse the code list (previously reversed by the
  143. ;;;       first pass), returning it to forward order.
  144. ;;;
  145. ;;;    2. Eliminate dead code
  146. ;;;
  147. ;;;       Delete instructions whenever the destination register is dead and
  148. ;;;       there are no side effects.
  149. ;;;
  150. ;;;       Maintain live/dead info: destination registers are dead prior to
  151. ;;;       assignment, source registers become live.  LIVE directives and
  152. ;;;       arguments to CALLs also control liveness.
  153. ;;;
  154. ;;;       Assumption: every JUMP is immediately preceded by a LIVE.
  155. ;;;
  156. ;;;    3. Target registers
  157. ;;;
  158. ;;;       Delay register moves (only), such as (LOAD A B).  Mark register A
  159. ;;;       as dead, register B as live.
  160. ;;;
  161. ;;;       Force delayed loads whenever register A is used or a label, CALL,
  162. ;;;       or JUMP occurs.
  163. ;;;
  164. ;;;       Substitute register A for register B and remove the (LOAD A B)
  165. ;;;       from the delayed list whenever register B is the destination of
  166. ;;;       an instruction.
  167. ;;;
  168. ;;;    4. Other optimizations
  169. ;;;
  170. ;;;       Eliminate no-ops:  (LOAD A A)
  171. ;;;
  172. ;;;       Commute operands:  (+ A B A) ==> (+ A A B)
  173. ;;;
  174. ;;;
  175. ;;; Data Structures:
  176. ;;;
  177. ;;;    REG-TABLE [0..63]
  178. ;;;
  179. ;;;       Entry I is #F iff register I is "live"
  180. ;;;
  181. ;;;    DELAY-LIST
  182. ;;;
  183. ;;;       "Delayed" register moves are maintained in the form:
  184. ;;;
  185. ;;;                        ((LOAD Ai Bi) ...)
  186. ;;;
  187. ;;;       where each Ai and Bi is a register number, no Ai=Aj, no Ai=Bj,
  188. ;;;       and no Bi=Bj.  The P2-DELAY routine decides whether to delay a
  189. ;;;       given (LOAD A B), based on the following considerations:
  190. ;;;
  191. ;;;       (= A B)  : Can't happen, because P2 previously deletes these
  192. ;;;       no-ops [p2-dead].
  193. ;;;
  194. ;;;       (= A Ai) : Can't happen, because Ai is "dead" and P2 would have
  195. ;;;       deleted this operation [p2-dead].
  196. ;;;
  197. ;;;       (= A Bi) : Can't happen, because P2 would previously have
  198. ;;;       substituted the corresponding Ai for A [p2-substitute], making
  199. ;;;       this (LOAD Ai B), and no Ai=Bj.  (???)
  200. ;;;
  201. ;;;       (= B Ai) : Can't happen, because P2 would have forced out any
  202. ;;;       delayed (LOAD Ai Bi) [p2-sources].
  203. ;;;
  204. ;;;       (= B Bi) : CAN happen.  We modify the current instruction so we
  205. ;;;       can continue to delay the previous (LOAD Ai Bi), as follows.
  206. ;;;
  207. ;;;          Example:   (load 3 5) ... (load 4 5)
  208. ;;;
  209. ;;;             When we see the (LOAD 3 5), we have already delayed the
  210. ;;;             (LOAD 4 5).  Thus, we change (LOAD 3 5) into (LOAD 3 4),
  211. ;;;             make register 4 "live", and continue to delay (LOAD 4 5).
  212. ;;;
  213. ;;;      B is live : CAN happen.  Don't delay the load, since the values
  214. ;;;      of both A and B are needed.
  215. ;;;
  216. ;;;       otherwise : delay the (LOAD A B).
  217. ;;;
  218.  
  219.   (peep2
  220.    (lambda (code)
  221.      (cond (pcs-permit-peep-2 (p2 code '()))
  222.        (pcs-permit-peep-1 (%reverse! code))
  223.        (else code))))
  224.  
  225.   (p2
  226.    (lambda (next acc)
  227.      (if (null? next)
  228.      acc
  229.      (let ((rest  (cdr next))
  230.            (instr (car next)))
  231.        (begin
  232.           (set-cdr! next acc)   ; assume we will keep it
  233.           ;; don't use ACC past here
  234.           (if (or (atom? instr)
  235.               (number? (car instr)))
  236.           (p2 rest (p2-force-all next))        ; label
  237.           (let ((op (car instr)))
  238.             (cond
  239.                ((eq? op 'JUMP)            ; JUMP
  240.             (p2-jump instr rest next))
  241.  
  242.                ((eq? op 'CALL)            ; CALL
  243.             (p2-call instr rest next))
  244.  
  245.                ((eq? op 'LIVE)            ; LIVE
  246.             (p2-live instr rest next))
  247.  
  248.                ((p2-dead? instr)        ; result not needed
  249.             (p2 rest (cdr next)))        ; delete it
  250.  
  251.                (else
  252.             (p2-substitute instr)
  253.             (if (eq? op 'LOAD)
  254.                 (p2-load instr rest next)
  255.                 (begin
  256.                    (let ((dest (cadr instr)))
  257.                  (when (number? dest)
  258.                     (p2-force dest next delay-list '())
  259.                     (p2-kill dest)))
  260.                    (p2-sources     ; make the src regs live
  261.                   (cddr instr) next)
  262.                    (p2-keep rest instr next))))))))))))
  263.  
  264.  
  265. ;;; p2-jump -- Process JUMP instructions.
  266.  
  267.   (p2-jump
  268.    (lambda (instr rest next)
  269.      (p2 rest
  270.      (p2-sources (cdddr instr)
  271.              (p2-force-all next)))))
  272.  
  273.  
  274. ;;; p2-call -- Process CALL instructions.
  275.  
  276.   (p2-call
  277.    (lambda (instr rest next)
  278.      (vector-fill! reg-table #T)            ; make all regs dead
  279.      (let ((next (p2-sources (cddr instr) 
  280.                  (p2-force-all next)))) ; make src regs live
  281.        (if (not (atom? (caddr instr)))
  282.        (p2-make-live 1 (car (caddr instr))))    ; number of args
  283.        (p2 rest next))))
  284.  
  285. ;;; p2-live -- Process LIVE directives.
  286.  
  287.   (p2-live
  288.    (lambda (instr rest next)
  289.      (vector-fill! reg-table #T)        ; make all regs dead
  290.      (let ((range (cadr instr)))        ; then make some live
  291.        (when (not (null? range))
  292.          (p2-make-live (car range)(cdr range))))
  293.      (p2 rest next)))
  294.  
  295.   (p2-make-live
  296.    (lambda (lo hi)
  297.      (when ( >= hi lo)
  298.        (vector-set! reg-table hi #F)   ; make reg live
  299.        (p2-make-live lo (sub1 hi)))))
  300.  
  301. ;;; p2-load -- Process LOAD instructions.
  302.  
  303.   (p2-load
  304.    (lambda (instr rest next)
  305.      (let ((dest (cadr instr))
  306.        (src  (caddr instr)))
  307.        (if (equal? dest src)         ; no-op?
  308.        (p2 rest (cdr next))      ; delete it
  309.        (let ((live-src? (and (number? src)
  310.                  (null? (vector-ref reg-table src)))))
  311.          (p2-force dest next delay-list '())
  312.          (p2-kill dest)
  313.          (p2-sources (cddr instr) next)
  314.          (let ((acc (cdr next)))
  315.            (if (and (not live-src?)
  316.             (p2-delay next))  ; does (set-cdr! next ...)
  317.            (p2 rest acc)
  318.            (p2-keep rest instr next))))))))
  319.  
  320. ;;; p2-substitute -- Attempt to substitute a delayed register for the
  321. ;;; destination of INSTR.  If the destination of INSTR is B and a 
  322. ;;; (LOAD A B) instruction has been delayed, then the destination is
  323. ;;; changed to A and the (LOAD A B) is forgotten.
  324. ;;;
  325. ;;; This substitution cannot be performed on variable-length instructions because
  326. ;;; they assume the destination is the same as the third operand (instead of 1st)
  327. ;;; (at this level, call format is: (%instr dest (quote len) r1=dest r2 ...) ).
  328. ;;; In this case, first arg (dest) won't be assembled by pasm.    (mv)
  329.  
  330.   (p2-substitute
  331.    (lambda (instr)
  332.      (letrec ((loop
  333.              (lambda (reg old new)
  334.            (if (null? old)
  335.                new
  336.                (let ((next (cdr old))
  337.                  (src  (caddr (car old))))
  338.              (if (and (= reg src)
  339.                       ; don't substitute for variable-length instr
  340.                                   (not (memq (car instr) '(%graphics %esc %mouse))))
  341.                  (begin            ; replace the dest opd
  342.                 (p2-kill (cadr instr))  ; kill old dest reg
  343.                     (set-car! (cdr instr)   ; subst new dest reg
  344.                       (cadr (car old)))
  345.                 (append! next new))     ; forget it
  346.                  (begin
  347.                     (set-cdr! old new)
  348.                 (loop reg next old))))))))
  349.       (if delay-list
  350.           (let ((dest (cadr instr)))
  351.         (if (number? dest)
  352.             (set! delay-list
  353.               (loop dest delay-list '()))))))))
  354.  
  355.  
  356. ;;; p2-kill -- Mark the register DEST as "dead".
  357.  
  358.   (p2-kill
  359.    (lambda (dest)
  360.      (if (number? dest)
  361.          (vector-set! reg-table dest #T))))
  362.  
  363.  
  364. ;;; p2-sources -- Process the source registers (SS) of an instruction:
  365. ;;;   1. Mark each source register as "live".
  366. ;;;   2. For each source operand OPD which is a register for which there is
  367. ;;;      a delayed assignment, force out the load, since this is the last
  368. ;;;      use of a previous value.
  369. ;;;   3. Return the updated code list, NEXT.
  370.  
  371.   (p2-sources
  372.    (lambda (ss next)
  373.      (if (null? ss)
  374.      next
  375.      (let ((opd (car ss)))
  376.        (if (number? opd)                ; register
  377.            (begin
  378.           (vector-set! reg-table opd #F)    ; make it live
  379.           (p2-sources (cdr ss) 
  380.                   (p2-force opd next delay-list '())))
  381.            (p2-sources (cdr ss) next))))))
  382.  
  383.  
  384. ;;; p2-force -- REG is a register which is being used as a source operand
  385. ;;; of the instruction which is at the head of CODE-LIST.  Thus, we must
  386. ;;; force out any delayed load which defines or uses REG, since the source
  387. ;;; operand must refer to the old value before reassignment (defines) and
  388. ;;; we can't eliminate registers with multiple uses.  Returns the updated
  389. ;;; CODE-LIST.
  390.  
  391.   (p2-force
  392.    (lambda (reg code-list old new)
  393.      (if (null? old)
  394.      (begin
  395.         (set! delay-list new)
  396.         code-list)
  397.      (let ((this (cdr old))
  398.            (dest (cadr (car old)))
  399.            (src  (caddr (car old))))
  400.        (if (or (= reg dest)
  401.            (= reg src))
  402.            (begin
  403.           (set-cdr! old (cdr code-list))
  404.           (set-cdr! code-list old)
  405.           (set! delay-list (append! this new))
  406.           code-list)
  407.            (begin
  408.           (set-cdr! old new)
  409.           (p2-force reg code-list this old)))))))
  410.  
  411.  
  412. ;;; p2-force-all -- Force all delayed register assignments out.  This is
  413. ;;; necessary at all jumps, calls, labels, etc.
  414.  
  415.   (p2-force-all
  416.    (lambda (code-list)
  417.      (when delay-list
  418.        (set-cdr! code-list
  419.              (append! delay-list (cdr code-list)))
  420.        (set! delay-list '()))
  421.      code-list))
  422.  
  423.  
  424. ;;; p2-delay -- Delay instructions of the form (LOAD reg-A reg-B)
  425.  
  426.   (p2-delay
  427.    (lambda (next)
  428.      (let ((instr (car next)))
  429.        (let ((dest (cadr instr))
  430.          (src  (caddr instr)))
  431.      (if (number? src)
  432.          (let ((delayed-load (p2-lookup src delay-list)))
  433.            (if delayed-load
  434.            (let ((delayed-dest (cadr delayed-load)))
  435.              (set-car! (cddr instr)
  436.                    delayed-dest)     ; fix this one
  437.              (p2-make-live delayed-dest
  438.                    delayed-dest) ; keep the other delayed
  439.              '())
  440.            (begin        ; delay this one
  441.               (set-cdr! next delay-list)
  442.               (set! delay-list next)
  443.               '#!TOKEN)))
  444.          '())))))             ; not a reg-reg move
  445.  
  446.   (p2-lookup
  447.    (lambda (src dl)
  448.      (cond ((null? dl)                 '())
  449.            ((= src (caddr (car dl)))   (car dl))
  450.            (else                          (p2-lookup src (cdr dl))))))
  451.  
  452.  
  453. ;;; p2-dead? -- Determine whether instruction INSTR may be considered
  454. ;;; redundant and thus deleted.  If the destination operand is "dead" and
  455. ;;; the instruction has no side effects, then the instruction is "dead".
  456.  
  457.   (p2-dead?
  458.    (lambda (instr)
  459.      (and (eq? (car instr) 'LOAD)            ; no side effects
  460.       (number? (cadr instr))            ; dest reg
  461.       (or (equal? (cadr instr)(caddr instr))
  462.           (not (null? (vector-ref reg-table (cadr instr))))))))
  463.  
  464.  
  465. ;;; p2-keep -- Keep the current instruction, INSTR (which is also the first
  466. ;;; item in NEXT).  If INSTR is a primitive that requires the first source
  467. ;;; operand to be the same as the destination register, add an appropriate
  468. ;;; LOAD in front and modify the instruction.
  469.  
  470.   (p2-keep
  471.    (lambda (rest instr next)
  472.      (let ((dest (cadr instr))
  473.        (src  (and (cddr instr)(caddr instr))))
  474.        (cond ((or (not (number? dest))
  475.               (not (number? src))
  476.               (= dest src)
  477.               (memq (car instr) funny-primitives))
  478.           (p2 rest next))
  479.          ((member dest (cdddr instr)) 
  480.           (if (and (memq (car instr) commutative-primops)
  481.                (equal? dest (cadddr instr)))
  482.           (begin                    ; swap source operands
  483.              (set-car! (cddr instr) dest)
  484.              (set-car! (cdddr instr) src)
  485.              (p2 rest next))
  486.           (begin
  487.              (set-cdr! next (cons (list 'LOAD dest 63)
  488.                       (cdr next)))
  489.              (set-car! (cdr instr) 63)
  490.              (set-car! (cddr instr) 63)
  491.              (p2 rest (cons (list 'LOAD 63 src) next)))))
  492.          (else
  493.           (set-car! (cddr instr) dest)
  494.           (p2 rest (cons (list 'LOAD dest src) next)))))))
  495.  
  496.  
  497. ;;; data
  498.  
  499.   (funny-primitives '(LOAD cons car cdr caar cadr cdar cddr caaar caadr
  500.               cadar caddr cdaar cdadr cddar cdddr cadddr))
  501.  
  502.   (commutative-primops '(+ * = eq? eqv? equal? max min))
  503.  
  504.   (delay-list     '())
  505.   (reg-table-max  0)
  506.   (reg-table      (make-vector 64 #F))
  507.  
  508. ;----!
  509.       )  
  510.      (begin
  511.         (when pcs-verbose-flag
  512.           (writeln "Codegen results:")
  513.           (pcs-princode code)
  514.           (newline))
  515.     (let ((code1 (peep1 code)))
  516.       (when pcs-verbose-flag
  517.         (writeln "Pass 1 optimization results:")
  518.         (set! code1 (%reverse! code1))
  519.         (pcs-princode code1)
  520.         (set! code1 (%reverse! code1))
  521.         (newline))
  522.       (let ((code2 (peep2 code1)))
  523.         (when pcs-verbose-flag
  524.           (writeln "Pass 2 optimization results:")
  525.           (pcs-princode code2)
  526.           (newline))
  527.         code2))))))
  528.  
  529.  
  530. (define pcs-princode                    ; PCS-PRINCODE
  531.   (lambda (code)
  532.     (letrec
  533.      (
  534. ;----!
  535.  
  536.   (tab  "    ")
  537.   (tab2 "        ")
  538.   (nlabels 0)
  539.   (ninstrs 0)
  540.   (nfields 0)
  541.  
  542.   (pcl
  543.       (lambda (cl)
  544.     (newline)
  545.     (when cl
  546.           (let ((x (car cl)))
  547.         (if (or (atom? x)            ; label?
  548.             (number? (car x)))
  549.             (begin
  550.               (set! nlabels (add1 nlabels))
  551.               (princ tab)
  552.               (princ x))     ; label
  553.             (begin
  554.               (set! ninstrs (add1 ninstrs))
  555.               (princ tab2)
  556.               (pc x tab)))       ; instruction
  557.         (pcl (cdr cl))))))
  558.  
  559.   (pc
  560.       (lambda (x spacer)
  561.     (set! nfields (add1 nfields))
  562.     (princ (car x))
  563.     (when (cdr x)
  564.           (princ spacer)
  565.           (pc (cdr x) ", "))))
  566.  
  567. ;----!
  568.       )
  569.      (pcl code)
  570.      (writeln "    There are " nlabels " labels, "
  571.                            ninstrs " instructions, and "
  572.                    nfields " fields.")
  573.      )))
  574.